/*
如何手写一个堆
1.插入一个数             heap[ ++ size] = x; up(size)
2.求集合中的最小值        heap[1];堆顶元素
3.删除最小值             heap[1] = heap[size]; size--;down(1) 用最后一个覆盖第一个，删除最后一个，然后做down
4.删除任意一个元素        heap[k] = heap[size]; size--; down(k); up(k);
5.修改任意一个元素        heap[k] = x; size--; down(k); up(k); 变大往下，变小往上
*/
/*
基本原理：优先级队列差不多，用一维数组去存数据
父节点下标：x
左儿子下标：2x
右儿子下标：2x+1
【注】根节点下标从1开始
*/

#include<iostream>

using namespace std;

const int N = 100010;
int n, m;
int head[N], size;

void down(int u){
    int t = u;
    if(2 * u < size && head[2*u] < head[t]) t = 2*u;
    if(2 * u + 1< size && head[2*u + 1] < head[t]) t = 2*u + 1;
    //if(head[2*u + 1] < head[2*u]) swap(head[2*u + 1], head[2*u]);
    if(t != u){
        swap(head[t], head[u]);
        down(t);
    }
}

void up(int u){
    while(u / 2 && head[u/2] > head[u]){
        swap(head[u/2], head[u]);
        u /= 2;
    }
}

int main(){
    scanf("%d%d", &n, &m);

    for(int i = 1; i < n; ++ i) scanf("%d", &head[i]);
    size = n;
    //细节：从n/2开始构建堆的速度快 可证明是O(n)
    for(int i = n/2; i; --i){
        down(i);
    }
    
    while(m --){
        printf("%d ", head[1]);
        head[1] = head[size];
        size--;
        down(1);
    }
    return 0;
}
